﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static SerialPortTest.Serial_cfg;

namespace SerialPortTest
{
    public class SerialTool
    {
        bool _continue;
        SerialPort _serialPort;
        Serial_cfg _cfg;
        Thread _readThread;
        ISerialRecv _recver;

        List<byte[]> _send_buffer = new List<byte[]>();
        object _sendbuff_lock = new object();

        byte[] _buff = new byte[1024];

        public void Init(ISerialRecv recv, Serial_cfg seri_cfg)
        {
            _recver = recv;
            _cfg = seri_cfg;

            //使用默认设置创建新的SerialPort
            _serialPort = new SerialPort();

            //设置值
            _serialPort.PortName = _cfg.PortName;
            _serialPort.BaudRate = (int)_cfg.BaudRate;
            _serialPort.Parity = _cfg.Party;
            _serialPort.DataBits = (int)_cfg.DataBits;
            _serialPort.StopBits = _cfg.StopBits;

            _serialPort.ReadTimeout = 300;
            _serialPort.WriteTimeout = 300;

            _continue = true;
        }

        //发送串口数据
        public void Send(byte[] buff)
        {
            lock(_sendbuff_lock)
                _send_buffer.Add(buff);

            if (buff == null || buff.Length < 1) return;

            if (!_serialPort.IsOpen)
                Open();

            if (!_serialPort.IsOpen)
            {
                Console.WriteLine($"串口打开失败，数据无法发送。 port:{_serialPort.PortName}");
            }

            ThreadPool.QueueUserWorkItem(p => { _serialPort.Write(buff, 0, buff.Length); });
        }

        //打开串口
        public void Open()
        {
            bool is_open = false;
            try
            {
                _serialPort.Open();
                is_open = _serialPort.IsOpen;
            }
            catch (Exception ex) { };

            string info = "";

            if (!is_open)
                info = "串口打开失败,请检查串口是否被占用或不存在";
            else
                info = "串口打开成功";

            Console.WriteLine($"=== 串口[{_serialPort.PortName}]，{info} 配置参数: {_cfg}");

            if (_readThread != null) return;

            _readThread = new Thread(ThreadProc_Read);
            _readThread.Name = $"[{_cfg.PortName}]：自定义的收发线程";
            _readThread.Start();
        }
        public void Close()
        {
            _continue = false;
            _readThread.Join();
            _readThread = null;
        }
        private void ThreadProc_Read()
        {
            List<byte[]> tmp = new List<byte[]>();

            while(_continue)
            {
                try
                {
                    if(!_serialPort.IsOpen)
                    {
                        _serialPort.Open();
                        Thread.Sleep(100);
                        continue;
                    }
                    //获取发送数据 进行发送
                    tmp.Clear();
                    if(_send_buffer.Count > 0)
                    {
                        lock(_sendbuff_lock)
                        {
                            tmp.AddRange(_send_buffer);
                            _send_buffer.Clear();
                        }
                    }
                    if(_send_buffer.Count > 0)
                    {
                        foreach(var send_val in tmp)
                        {
                            Console.WriteLine($"[{_serialPort.PortName}]口,发送: {Convert2Hex(send_val)}");
                            _serialPort.Write(send_val,0,send_val.Length);

                            Thread.Sleep(5);
                        }
                    }
                    //读取串口数据 
                    var can_read_count = _serialPort.BytesToRead;

                    if(can_read_count < 1)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    int recv = _serialPort.Read(_buff,0,1024);
                    if(_recver != null && recv > 0)
                    {
                        byte[] send_buff = new byte[recv];
                        Array.Copy(_buff,send_buff,recv);

                        ThreadPool.QueueUserWorkItem(p => { _recver.On_serial_recved(send_buff, _cfg); });
                    }
                }catch(Exception)
                {
                    Thread.Sleep(1000);
                }

            }
        }

        public static string Convert2Hex(byte[] val)
        {
            if (val == null)
                return null;

            StringBuilder sb = new StringBuilder();
            foreach (byte bt in val)
            {
                sb.Append(bt.ToString("X2"));
                sb.Append(" ");
            }
            return sb.ToString();
        }
    }
}
